package com.qf.smartdevice.websocket.handler;

import com.qf.smartdevice.events.DevicePowerEvent;
import com.qf.smartdevice.events.enums.DeviceStatus;
import com.qf.smartdevice.events.enums.DeviceStatusCheckEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 王博康
 * @version 1.0
 * @project devicemanagementsystem
 * @description: TODO
 * @date 2022/3/27 1:16 星期日
 */
@Component
public class powerCommandHandler extends TextWebSocketHandler {

    private ApplicationContext context;

    @Autowired
    public void setContext(ApplicationContext context) {
        this.context = context;
    }

    //保存所有连接的集合
    private static ConcurrentHashMap<String,WebSocketSession> allconn=new ConcurrentHashMap<>();

    //保存设备最后一次心跳时间的集合
    private static ConcurrentHashMap<String,Long> lastHeartBeatMap=new ConcurrentHashMap<>();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        String uri = session.getUri().toString();
        String deviceKey = uri.substring(uri.lastIndexOf("/") + 1);
        System.err.println(deviceKey+"设备创建连接了");
        //方便之后使用
        session.getAttributes().put("deviceKey",deviceKey );
        WebSocketSession socketSession = allconn.get(deviceKey);
        //检查该标识是否连接过
        if (socketSession!=null){
            //代表该标识已连接过,应关闭
            socketSession.close();//关闭方法会从缓存中删除
        }
        //保存会话
        allconn.put(deviceKey,session );
        //连接时当作一次心跳
        lastHeartBeatMap.put(deviceKey,System.currentTimeMillis() );
        //todo:设备连接后应操作数据库,故此发布通知,并携带所需信息
        context.publishEvent(new DevicePowerEvent(deviceKey, session.getRemoteAddress().getHostString(), DeviceStatus.ONLINE ));
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        //记录心跳时间
        String deviceKey = (String) session.getAttributes().get("deviceKey");
        lastHeartBeatMap.put(deviceKey,System.currentTimeMillis() );
        System.err.println(deviceKey+"设备收到消息"+message.getPayload());
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        System.err.println("设备连接发生异常了");
        super.handleTransportError(session, exception);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String deviceKey = (String) session.getAttributes().get("deviceKey");
        System.err.println(deviceKey+"设备断开连接了");
        //从缓存中删除连接
        allconn.remove(deviceKey);
        //todo:发布通知,更改设备状态
        context.publishEvent(new DevicePowerEvent(deviceKey,session.getRemoteAddress().getHostString() ,DeviceStatus.OFFLINE ));
    }

    @EventListener
    public void onEvent(DeviceStatusCheckEvent event){
        System.err.println("设备心跳检查开始...");
        allconn.entrySet().parallelStream().forEach(stringWebSocketSessionEntry -> {
            String deviceKey = stringWebSocketSessionEntry.getKey();
            WebSocketSession socketSession = stringWebSocketSessionEntry.getValue();
            Long lastHeartBeatTime = lastHeartBeatMap.get(deviceKey);
            if (System.currentTimeMillis()-lastHeartBeatTime>30000){
                //当检测到心跳超时时,关闭连接
                if (socketSession.isOpen()) {
                    try {
                        socketSession.close();//连接关闭时,会自动从连接缓存中删除设备
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                //从存储心跳信息的缓存中移除设备
                lastHeartBeatMap.remove(deviceKey);
            }
        });

    }
}
